package com.liuxinlong.modules.common.service.impl;

import com.liuxinlong.common.AosException;
import com.liuxinlong.common.SnowFlake;
import com.liuxinlong.constant.SystemConstants;
import com.liuxinlong.constant.ThreadLocalConstants;
import com.liuxinlong.constant.TimeFormatConstants;
import com.liuxinlong.enums.MatterSourceEnum;
import com.liuxinlong.enums.NotificationSourceEnum;
import com.liuxinlong.enums.RedisKeyEnum;
import com.liuxinlong.enums.ReturnCodes;
import com.liuxinlong.modules.common.entity.UserHeaderDto;
import com.liuxinlong.modules.common.service.CommonService;
import com.liuxinlong.modules.dao.DepartmentDao;
import com.liuxinlong.modules.dao.FileManageDao;
import com.liuxinlong.modules.dao.NotificationDao;
import com.liuxinlong.modules.dao.ParameterDao;
import com.liuxinlong.modules.dao.ProjectDao;
import com.liuxinlong.modules.dao.UserDao;
import com.liuxinlong.modules.dao.UserFollowDao;
import com.liuxinlong.modules.dao.UserMatterDao;
import com.liuxinlong.modules.dao.UserRoleRelationDao;
import com.liuxinlong.modules.entity.FileManage;
import com.liuxinlong.modules.entity.Notification;
import com.liuxinlong.modules.entity.Project;
import com.liuxinlong.modules.entity.SystemParameter;
import com.liuxinlong.modules.entity.User;
import com.liuxinlong.modules.entity.UserFollow;
import com.liuxinlong.modules.entity.UserMatter;
import com.liuxinlong.modules.entity.UserRoleRelation;
import com.liuxinlong.modules.system.service.UserService;
import com.liuxinlong.utils.IPUtils;
import com.liuxinlong.utils.ObjectUtils;
import com.liuxinlong.utils.RedisUtils;
import com.liuxinlong.utils.ThreadlocalUtils;
import com.liuxinlong.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 通用数据接口实现
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2022-03-01
 */
@Service
@Slf4j
public class CommonServiceImpl implements CommonService {

    @Autowired
    private ParameterDao parameterDao;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private NotificationDao notificationDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    private UserRoleRelationDao userRoleRelationDao;

    @Autowired
    private UserMatterDao userMatterDao;

    @Autowired
    private FileManageDao fileManageDao;

    @Autowired
    private UserFollowDao userFollowDao;

    @Autowired
    private UserService userService;

    @Autowired
    private ProjectDao projectDao;

    @Override
    public String generateStandardCode() {
        SystemParameter sp = parameterDao.getParameterByName(SystemConstants.GENERATE_CODE_PARAM);
        if (ObjectUtils.isEmpty(sp)) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR);
        }
        int currentSn = Integer.parseInt(sp.getValue());
        currentSn++;
        return "AOSTES" + currentSn;
    }

    @Override
    public String generateEcrCode() {
        SystemParameter sp = parameterDao.getParameterByName(SystemConstants.GENERATE_ECR_PARAM);
        if (ObjectUtils.isEmpty(sp)) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR);
        }
        int currentSn = Integer.parseInt(sp.getValue());
        currentSn++;
        return "AOSECR" + currentSn;
    }

    @Override
    public String generateEcnCode() {
        SystemParameter sp = parameterDao.getParameterByName(SystemConstants.GENERATE_ECN_PARAM);
        if (ObjectUtils.isEmpty(sp)) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR);
        }
        int currentSn = Integer.parseInt(sp.getValue());
        currentSn++;
        return "AOSECN" + currentSn;
    }

    @Override
    public List<Map<String, Object>> getNotices() {
        List<Map<String, Object>> resultList = new ArrayList<>();
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("startNum", 0);
        queryMap.put("pageSize", 100);
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        queryMap.put("dealUser", current.getId());
        List<Notification> notificationList = notificationDao.pageNotification(queryMap);
        int sort = 1;
        for (Notification item : notificationList) {
            Map<String, Object> map = ObjectUtils.object2Map(item);
            map.put("key", sort);
            map.put("type", "notification");
            map.put("title", NotificationSourceEnum.getSourceNameByValue(item.getSourceType()));
            map.put("description", item.getContent());
            map.put("datetime", item.getCreateTime());
            map.put("read", item.getStatus() == 1 ? true : false);
            resultList.add(map);
            sort++;
        }
        queryMap.put("pendingUser", current.getId());
        queryMap.put("dealUser", null);
        queryMap.put("status", 0);
        List<UserRoleRelation> relationList = userRoleRelationDao.queryRelationByUserId(current.getId());
        List<String> roleList = relationList.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
        queryMap.put("roleList", roleList);
        List<UserMatter> pendingList = userMatterDao.pageUserMatter(queryMap);
        List<Map<String, Object>> needList = new ArrayList<>();
        int needSort = 1;
        for (UserMatter item : pendingList) {
            Map<String, Object> pendingMap = ObjectUtils.object2Map(item);
            pendingMap.put("key", needSort);
            pendingMap.put("type", "event");
            pendingMap.put("title", MatterSourceEnum.getNameByValue(item.getSourceType()));
            pendingMap.put("description", item.getContent());
            pendingMap.put("datetime", item.getCreateTime());
            pendingMap.put("sourceName", MatterSourceEnum.getNameByValue(item.getSourceType()));
            needList.add(pendingMap);
            sort++;
        }
        if (!ObjectUtils.isEmpty(resultList)) {
            resultList.addAll(needList);
            return resultList;
        }
        return needList;
    }

    @Override
    public Map<String, Object> queryUserHeader(String userId) {
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        UserFollow userFollow = userFollowDao.getUserFollowInfo(current.getId(), userId);
        boolean followFlag = ObjectUtils.isEmpty(userFollow);
        boolean currentFlag = StringUtils.equals(userId,current.getId());
        UserHeaderDto userHeaderDto = redisUtils.getUserHeaderCache(userId);
        if (!ObjectUtils.isEmpty(userHeaderDto)) {
            Map<String, Object> map = ObjectUtils.object2Map(userHeaderDto);
            map.put("followFlag", followFlag);
            map.put("currentFlag", currentFlag);
            return map;
        }
        UserHeaderDto userDto = new UserHeaderDto();
        User userDb = userDao.selectById(userId);
        userDto.setId(userId);
        userDto.setName(userDb.getName());
//        userDto.setPost(userDb.getPost());
//        userDto.setProfile(userDb.getProfile());
        if (!StringUtils.isEmpty(userDb.getPortrait())) {
            String currentIp = IPUtils.getCurrentIp();
            FileManage headerFile = fileManageDao.selectById(userDb.getPortrait());
            userDto.setPortrait(headerFile.getFilePath().replace("upload", "http:\\\\" + currentIp + ":8090\\preview\\upload"));
        }
        userDto.setAddress(userDb.getAddress());
//        userDto.setNickName(userDb.getAbbreviationName());
//        userDto.setEmail(userDb.getEmail());
        userDto.setDepartmentName(departmentDao.selectById(userDb.getDepartment()).getName());
        redisUtils.setUserHeaderCache(userId, userDto);
        Map<String, Object> map = ObjectUtils.object2Map(userDto);
        map.put("followFlag", followFlag);
        map.put("currentFlag", currentFlag);
        return map;
    }

    @Override
    public void changeReadState(String id) {
        notificationDao.updateState(id);
    }

    @Override
    public void clearReadState(String title) {
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        if (StringUtils.equals(title,"待办")) {
            userMatterDao.updateAllState(current.getId(),currentTime);
        } else if (StringUtils.equals(title,"消息")) {
            notificationDao.updateAllState(current.getId(),currentTime);
        }

    }

    @Override
    public int getOnlineCount() {
        Set<String> keyGroupCache = redisUtils.getKeyGroupCache(RedisKeyEnum.USER_LOGIN_CACHE.getKey());
        return keyGroupCache.size();
    }

    @Override
    @Transactional
    public void followUser(String userId) {
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        if (ObjectUtils.isEmpty(current)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "用户不存在！");
        }
        if (StringUtils.equals(userId, current.getId())) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "不可以关注自己！");
        }
        User targetUser = userDao.selectById(userId);
        if (ObjectUtils.isEmpty(targetUser)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "关注用户不存在！");
        }
        UserFollow follow = userFollowDao.getUserFollowInfo(current.getId(), userId);
        if (ObjectUtils.isEmpty(follow)) {
            UserFollow userFollow = new UserFollow();
            userFollow.setId(SnowFlake.nextIdStr());
            userFollow.setUserId(current.getId());
            userFollow.setFollowId(userId);
            userFollow.setFollowTime(TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS));
            userFollowDao.insert(userFollow);
            Map<String, Object> redisData = redisUtils.getUserInfoCache(current.getId());
            if (ObjectUtils.isEmpty(redisData)) {
                userService.queryUserBase(current.getId());
            } else {
                redisData.put("follow", redisData.containsKey("follow") ? (int) redisData.get("follow") + 1 : 1);
                redisUtils.setUserInfoCache(current.getId(), redisData);
            }

            Map<String, Object> targetData = redisUtils.getUserInfoCache(userId);
            if (ObjectUtils.isEmpty(targetData)) {
                userService.queryUserBase(userId);
            } else {
                targetData.put("fans", targetData.containsKey("fans") ? (int) targetData.get("fans") + 1 : 1);
                redisUtils.setUserInfoCache(userId, targetData);
            }
        } else {
            userFollowDao.deleteById(follow.getId());
            Map<String, Object> redisData = redisUtils.getUserInfoCache(current.getId());
            if (ObjectUtils.isEmpty(redisData)) {
                userService.queryUserBase(current.getId());
            } else {
                redisData.put("follow", redisData.containsKey("follow") ? (int) redisData.get("follow") - 1 : 0);
                redisUtils.setUserInfoCache(current.getId(), redisData);
            }
            Map<String, Object> targetData = redisUtils.getUserInfoCache(userId);
            if (ObjectUtils.isEmpty(targetData)) {
                userService.queryUserBase(userId);
            } else {
                targetData.put("fans", targetData.containsKey("fans") ? (int) targetData.get("fans") - 1 : 0);
                redisUtils.setUserInfoCache(userId, targetData);
            }
        }
    }

    @Override
    public void dealNeedMatter(String id, String remark) {
        UserMatter userMatter = userMatterDao.selectById(id);
        if (ObjectUtils.isEmpty(userMatter) || userMatter.getStatus() == 1) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR,"待办事项不存在或已被处理！");
        }
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        userMatter.setStatus(1);
        userMatter.setDealUser(currentUser.getId());
        userMatter.setDealTime(currentTime);
        userMatter.setRemark(remark);
        userMatterDao.updateById(userMatter);
    }

    @Override
    public Map<String, Object> getProjectDetail(String id) {
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        Project project = projectDao.selectById(id);
        if (ObjectUtils.isEmpty(project)){
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR,"项目不存在！");
        }
        Map<String,Object> detaMap = ObjectUtils.object2Map(project);
        return detaMap;
    }
}
